import axios, { AxiosRequestConfig, AxiosResponse } from "axios";
import globalConfig from "@/config/global-config";
import { ElLoading, ElMessage } from "element-plus";
import qs from "qs";
import router from "@/router";

// 返还的数据类型, 由于无法解决返回值判断泛型的问题，无法在模板中使用.
export interface ResponseData<T> {
  status: number;
  statusText: string;
  data: {
    code: number;
    data?: T;
    msg: string;
  };
}

const {
  api: { devApiBaseUrl, proApiBaseUrl },
} = globalConfig;

const apiBaseUrl =
  process.env.NODE_ENV === "production" ? proApiBaseUrl : devApiBaseUrl;

// 响应出错时不同的状态弹出的不同的内容
const responseStatusMsg = (status: number) => {
  let message: string;
  switch (status) {
    case 400:
      message = "请求错误(400)";
      break;
    case 401:
      message = "未授权，请重新登录(401)";
      break;
    case 403:
      message = "拒绝访问(403)";
      break;
    case 404:
      message = "请求出错(404)";
      break;
    case 408:
      message = "请求超时(408)";
      break;
    case 500:
      message = "服务器错误(500)";
      break;
    case 501:
      message = "服务未实现(501)";
      break;
    case 502:
      message = "网络错误(502)";
      break;
    case 503:
      message = "服务不可用(503)";
      break;
    case 504:
      message = "网络超时(504)";
      break;
    case 505:
      message = "HTTP版本不受支持(505)";
      break;
    default:
      message = `连接出错(${status})!`;
  }
  return `${message}，请检查网络或联系管理员！`;
};

const service = axios.create({
  baseURL: apiBaseUrl,
  // 是否跨站点访问控制请求
  withCredentials: true,
  timeout: 3000,
  validateStatus() {
    // 使用async-await，处理reject情况较为繁琐，所以全部返回resolve，在业务代码中处理异常
    return true;
  },
  // 转换请求数据.
  // transformRequest: [
  //   (dataPeople) => {
  //     dataPeople = JSON.stringify(dataPeople);
  //     return dataPeople;
  //   },
  // ],
  // 转换接收的数据.
  // transformResponse: [
  //   (dataPeople) => {
  //     if (typeof dataPeople === "string" && dataPeople.startsWith("{")) {
  //       dataPeople = JSON.parse(dataPeople);
  //     }
  //     return dataPeople;
  //   },
  // ],
});

// 请求拦截器
service.interceptors.request.use(
  (config: AxiosRequestConfig) => {
    ElLoading.service({ text: "Loading..." });
    return config;
  },
  (error) => {
    ElMessage.error({ message: "请求超时" });
    return Promise.resolve(error);
  }
);
// 响应拦截器
service.interceptors.response.use(
  (res: AxiosResponse) => {
    ElLoading.service().close();
    const status = res.status;
    let msg = "";
    if (status < 200 || status >= 300) {
      // 处理http错误，抛到业务代码
      msg = responseStatusMsg(status);
      ElMessage.error({ message: msg });
      if (status == 401) {
        router.push("/login");
      }
      return Promise.reject(res);
    }
    if (!Object.prototype.hasOwnProperty.call(res.data, "code")) {
      // 对于一些数据，后端没有做封装，将直接获取其返还值进行处理.
      return res;
    } else {
      const code = res.data.code;
      if (code === 200) {
        if (res.config.method !== "get") {
          // 在大多数返回的数据后端都做了封装，只需要读出其中的data即可.
          ElMessage.success({ message: res.data.msg });
        }
        return res.data;
      } else if (code === 201) {
        //某些post请求成功时也不希望弹出提示
        return res.data;
      } else {
        if (
          res.data.msg === "" ||
          res.data.msg === null ||
          res.data.msg === undefined
        ) {
          ElMessage.error({ message: "失败" });
        } else {
          ElMessage.error({ message: res.data.msg });
        }
      }
    }
  },
  (error) => {
    ElLoading.service().close();
    if (axios.isCancel(error)) {
      console.log("repeated request: " + error.message);
    } else {
      // handle error code
      // 错误抛到业务代码
      error.data = {};
      error.data.msg = "请求超时或服务器异常，请检查网络或联系管理员！";
      ElMessage.error(error.data.msg);
    }
    return Promise.reject(error);
  }
);

const http = {
  // get
  async get(url: string) {
    return service.get(url);
  },
  async getJson(url: string) {
    return await service.get(url, {
      headers: { "Content-Type": "application/json" },
    });
  },
  async download(url: string) {
    return await service.get(url, { responseType: "arraybuffer" });
  },
  // post
  async post<T>(url: string, param: T) {
    return await service.post(url, qs.stringify(param));
  },
  async postJson<T>(url: string, param: T) {
    return await service.post(url, param, {
      headers: { "Content-Type": "application/json" },
    });
  },
  async upload<T>(url: string, data: T) {
    return await service.post(url, data, {
      headers: { "Content-Type": "multipart/form-dataPeople" },
    });
  },
  async put<T>(url: string, param: T) {
    return await service.put(url, qs.stringify(param));
  },
  async putJson<T>(url: string, param: T) {
    return await service.put(url, param, {
      headers: { "Content-Type": "application/json" },
    });
  },
  async delete(url: string) {
    return await service.delete(url);
  },
};

export default http;
